package com.zhongli.devplatform.controller.user;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.zhongli.devplatform.bean.SecurityUserData;
import com.zhongli.devplatform.bean.SecurityHelper;
import com.zhongli.devplatform.component.FileUtil;
import com.zhongli.devplatform.component.FollowUtil;
import com.zhongli.devplatform.constant.Consts;
import com.zhongli.devplatform.dto.user.ForgetPwdDTO;
import com.zhongli.devplatform.dto.user.RestPwdDTO;
import com.zhongli.devplatform.dto.user.UserInfoDTO;
import com.zhongli.devplatform.dto.user.UserRegisterDTO;
import com.zhongli.devplatform.po.common.*;
import com.zhongli.devplatform.po.teacher.ReadOperationPO;
import com.zhongli.devplatform.po.user.ReadUserParentPO;
import com.zhongli.devplatform.po.view.ViewUserPO;
import com.zhongli.devplatform.po.user.ReadUserAttFansPO;
import com.zhongli.devplatform.po.user.ReadUserInfoPO;
import com.zhongli.devplatform.po.user.ReadUserPO;
import com.zhongli.devplatform.service.imp.common.*;
import com.zhongli.devplatform.service.imp.student.ReadCommitOperationService;
import com.zhongli.devplatform.service.imp.student.ReadUserParentService;
import com.zhongli.devplatform.service.imp.sys.ReadSendSmsService;
import com.zhongli.devplatform.service.imp.teacher.ReadClazzNoticeService;
import com.zhongli.devplatform.service.imp.teacher.ReadNoticeService;
import com.zhongli.devplatform.service.imp.teacher.ReadOperationService;
import com.zhongli.devplatform.service.imp.user.ReadUserInfoService;
import com.zhongli.devplatform.service.imp.user.ReadUserService;
import com.zhongli.devplatform.service.imp.view.ViewUserService;
import com.zhongli.devplatform.utils.BeanCopierUtil;
import com.zhongli.devplatform.utils.StringUtils;
import com.zhongli.devplatform.bean.Res;
import com.zhongli.devplatform.utils.user.UserUtil;
import com.zhongli.devplatform.vo.common.SystemUserInfoVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import javax.validation.constraints.NotBlank;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author WuXiCheng
 * @version 1.0
 * @date 2020/7/23 14:49
 */
@Api(tags = "用户", description = "用户", value = "用户")
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private ReadUserService userService;

    @Autowired
    private ReadUserAttFansService userAttFansService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ViewUserService viewUserService;

    @Autowired
    private ReadTeachClazzService teachClazzService;

    @Autowired
    @Qualifier("huaweiSendSmsService")
    private ReadSendSmsService sendSmsService;

    @Autowired
    private ReadUserInfoService userInfoService;

    @Autowired
    private ReadNoticeService noticeService;

    @Autowired
    private ReadClazzService clazzService;


    @Autowired
    private ReadUserParentService userParentService;

    @Autowired
    private ReadClazzOperationService clazzOperationService;

    @Autowired
    private ReadOperationService operationService;

    @Autowired
    private ReadCommitOperationService commitOperationService;

    @Autowired
    private ReadClazzNoticeService clazzNoticeService;

    @Autowired
    private ZSetOperations<String,Object> zSetOperations;


    @Autowired
    private FollowUtil followUtil;

    @Autowired
    private FileUtil fileUtil;

    @ApiOperation("注册")
    @PostMapping("/register")
    public Res register(@RequestBody UserRegisterDTO userRegisterDTO){

        return userService.register(userRegisterDTO);
    }

    @ApiOperation(value = "发送手机验证码", notes = "param: register")
    @GetMapping("/getCode")
    public Res getCode(@RequestParam("phone") String phone) {
        String redisKey = Consts.PHONE_CODE + phone;
        String code = StringUtils.getVerifyCode(6);
        try {
            sendSmsService.send("huawei_sms_template_key",phone,code);
            stringRedisTemplate.opsForValue().set(redisKey, code,5, TimeUnit.MINUTES);
            return Res.ok( "发送成功");
        } catch (Exception e) {
            e.printStackTrace();
            return Res.not_ok( "发送失败");
        }
    }

    @ApiOperation(value = "校验手机验证码", notes = "")
    @GetMapping("/checkSmsCode")
    public Res checkSmsCode(@NotBlank(message = "手机号不能为空") String phone, @NotBlank(message = "短信验证码不能为空")  String smsCode) {
        String redisKey = Consts.PHONE_CODE  + phone;
        String cacheCode = stringRedisTemplate.opsForValue().get(redisKey);
        if (StrUtil.equals(smsCode, cacheCode)) {
            return Res.ok(true);
        }
        return Res.not_ok("验证码不正确");
    }

    /**
     * 忘记密码
     * @param forgetPwdDTO
     * @return
     */
    @ApiOperation("忘记密码")
    @PostMapping("/forgetPwd")
    public Res forgetPwd(@RequestBody ForgetPwdDTO forgetPwdDTO){
        return userService.forgetPwd(forgetPwdDTO.getPhone(),forgetPwdDTO.getVerifyCode(),forgetPwdDTO.getPassword());
    }


    /**
     * 修改密码
     * @param restPwdDTO
     * @return
     */
    @ApiOperation("重置密码")
    @PostMapping("/resetPwd")
    public Res resetPwd(@RequestBody RestPwdDTO restPwdDTO) {
        return userService.resetPwd(restPwdDTO.getPwd(),restPwdDTO.getNewPwd());
    }

    /**
     * 用户登出
     * @return
     */
    @ApiOperation("用户登出")
    @PostMapping(value = "/logout")
    public Res logout() {
        SecurityUserData currentUser = SecurityHelper.getCurrentUser();
        stringRedisTemplate.delete(Consts.USER_TOKEN + currentUser.getAccountNum());
        return Res.ok("退出成功");
    }


    /**
     * 修改当前用户的信息
     * @param userInfoDTO {@link UserInfoDTO} 用户的信息
     * @return 结果
     */
    @ApiOperation("修改当前用户的信息")
    @PutMapping("/updateCurrentUserInfo")
    public Res updateCurrentUserInfo(@RequestBody UserInfoDTO userInfoDTO){
        ReadUserInfoPO userInfoPO = BeanCopierUtil.copy(userInfoDTO, ReadUserInfoPO.class);
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        assert userInfoPO != null;
        if (!StringUtils.isEmpty(userInfoDTO.getHeadImgUrl())) {
            List<String> fileList = fileUtil.getFileList(userInfoDTO.getHeadImgUrl(), userInfoDTO.getFolder());
            userInfoPO.setHeadImgUrl(fileList.get(0));
        }
        userInfoService.update(userInfoPO, new UpdateWrapper<ReadUserInfoPO>().eq("user_id",currentUserId));
        return Res.ok("success");
    }

    @ApiOperation("获取用户系统固定信息")
    @GetMapping("getSystemUserInfo")
    public Res getSystemUserInfo(){
        Collection<? extends GrantedAuthority> authorities =
                SecurityContextHolder.getContext().getAuthentication().getAuthorities();
        Integer userId = SecurityHelper.getCurrentUserId();
        ReadUserPO userPO = userService.getById(userId);
        ViewUserPO viewUserPO = viewUserService.getOne(new QueryWrapper<ViewUserPO>().eq("user_id", userId));
        //封装
        List<String> list = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
        String[] strings = list.get(0).split("=");
        SystemUserInfoVO systemUserInfoVO = new SystemUserInfoVO();
        systemUserInfoVO.setRole(strings[1]);
        systemUserInfoVO.setId(userId);
        systemUserInfoVO.setSkinType(userPO.getSkinType());
        systemUserInfoVO.setHeadImgUrl(viewUserPO.getHeadImgUrl());
        systemUserInfoVO.setNickName(viewUserPO.getNickName());
        if ("student".equals(strings[1])){
            List<ReadClazzOperationPO> allOpera = clazzOperationService
                    .list(new QueryWrapper<ReadClazzOperationPO>().eq("clazz_id", userPO.getClazzId()));
            if (!allOpera.isEmpty()) {
                List<Integer> operaIds = allOpera.stream().map(ReadClazzOperationPO::getOperationId).collect(Collectors.toList());
                List<ReadOperationPO> operaList = operationService.listByIds(operaIds);
                Date date = new Date();//在开始时间内的作业题
                List<Integer> dateOperaIds = operaList.stream().filter(item -> (date.before(item.getEndTime()) && date.after(item.getStartTime())))
                        .map(ReadOperationPO::getId)
                        .collect(Collectors.toList());
                if (!dateOperaIds.isEmpty()) {
                    int operationCount = dateOperaIds.size();
                    //int operationCount = getOperationCount(operaIds);
                    int fished = commitOperationService.count(new QueryWrapper<ReadCommitOperationPO>()
                            .eq("student_id", userId)
                            .in("operation_id", dateOperaIds));
                    systemUserInfoVO.setUnfinishedOperation(operationCount - fished);
                }else {
                    systemUserInfoVO.setUnfinishedOperation(0);
                }
            }
        }
        systemUserInfoVO.setUnreadMessage(getUnreadMes(userPO.getClazzId(),userId));
        return Res.ok(systemUserInfoVO);
    }


    /**
     * 查询未读通知数
     * @param classId
     * @return
     */
    private int getUnreadMes(Integer classId, Integer userId){
        List<Integer> noticeIds = clazzNoticeService.
                list(new QueryWrapper<ReadClazzNoticePO>().eq("clazz_id", classId))
                .stream().map(ReadClazzNoticePO::getNoticeId).collect(Collectors.toList());
        if (noticeIds.isEmpty()) return 0;
        List<ReadNoticePO> noticePOS = noticeService.listByIds(noticeIds);
        return (int) noticePOS.stream().filter(item ->{
            if (StringUtils.isBlank(item.getNotifiedPersonIds())){
                return true;
            }else {
               return !item.getNotifiedPersonIds().contains(userId.toString());
            }
        }).count();
    }

    @ApiOperation("切换皮肤")
    @GetMapping("/updateSkinType/{skinType}")
    public Res updateSkinType(@PathVariable Integer skinType){
        Integer userId = SecurityHelper.getCurrentUserId();
        ReadUserPO userPO = userService.getById(userId);
        userPO.setSkinType(skinType);
        userService.updateById(userPO);
        return Res.ok("success");
    }

    /**
     * 获取当前用户的关注的用户列表
     * @return 结果
     */
    @ApiOperation("获取当前用户的关注的用户列表")
    @GetMapping("/getCurrentUserAtt")
    public Res getCurrentUserAtt(){
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        Set<String> fans = followUtil.findFollwings(currentUserId.toString());
        Set<Object> collect = fans.stream().map(String::valueOf).collect(Collectors.toSet());
        if (collect.size() > 0) {
            List<ReadUserInfoPO> data = userInfoService.list(new QueryWrapper<ReadUserInfoPO>().in("user_id",collect));
            return Res.ok(data);
        }else {
            return Res.ok(new ArrayList<>());
        }
    }


    /**
     * 获取当前用户的关注的用户列表
     * @return 结果
     */
    @ApiOperation("获取当前用户的粉丝列表")
    @GetMapping("/getCurrentUserFans")
    public Res getCurrentUserFans(){
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        Set<String> fans = followUtil.findFans(currentUserId.toString());
        Set<Object> collect = fans.stream().map(String::valueOf).collect(Collectors.toSet());
        if (collect.size() > 0) {
            List<ReadUserInfoPO> data = userInfoService.list(new QueryWrapper<ReadUserInfoPO>().in("user_id",collect));
            return Res.ok(data);
        }else {
            return Res.ok(null);
        }
    }


    @ApiOperation("用户关注/取消------------------用户的关注或者取消关注")
    @PostMapping("/like/{userId}")
    public Res postLikeVideo(@PathVariable Integer userId){
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        followUtil.addOrRelease(currentUserId.toString(),userId.toString());
        //String key = Consts.USER_ATT + userId;
        //int i = followUtil.checkRelations(currentUserId.toString(), userId.toString());
        //if (i == 2){
        //    zSetOperations.remove(key,currentUserId);
        //}else {
        //    zSetOperations.add(key,currentUserId,new Date().getTime());
        //}
        /*QueryWrapper<ReadUserAttFansPO> queryWrapper =new QueryWrapper<ReadUserAttFansPO>()
                .eq("from_user_id", currentUserId)
                .eq("to_user_id",userId);
        ReadUserAttFansPO attFansPOS = userAttFansService.getOne(queryWrapper);
        if (attFansPOS == null){//没有就点赞
            ReadUserAttFansPO po = new ReadUserAttFansPO();
            po.setFromUserId(currentUserId);
            po.setToUserId(userId);
            userAttFansService.save(po);
        }else {//有就取消点赞
            userAttFansService.remove(queryWrapper);
        }*/
        return Res.ok("success");
    }

    @ApiOperation("用户获取粉丝数量 和有没有关注")
    @GetMapping("/fansCount/{userId}")
    public Res<HashMap<String, Object>> getFansCount(@PathVariable Integer userId){
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        Long count = zSetOperations.size(Consts.USER_FANS + userId);
        int isAtt = followUtil.checkRelations(currentUserId.toString(),userId.toString());
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("fansCount",count);
        hashMap.put("isAtt",isAtt == 2);
        return Res.ok(hashMap);
    }



    @ApiOperation("用户获取关注数量 和有没有关注")
    @GetMapping("/AttCount")
    public Res<Integer> getAttCount(){
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        Set<String> att = followUtil.findFollwings(currentUserId.toString());
        return Res.ok(att.isEmpty()?0:att.size());
    }



    @ApiOperation("用户关注详情")
    @GetMapping("/likeDetail/{userId}")
    public Res getLikeDetail(@PathVariable Integer userId){
        QueryWrapper<ViewUserPO> queryWrapper =new QueryWrapper<ViewUserPO>()
                .eq("user_id", userId);
        ViewUserPO one = viewUserService.getOne(queryWrapper);
        ReadUserAttFansPO attFansPOS = userAttFansService.getOne(
                new QueryWrapper<ReadUserAttFansPO>()
                .eq("from_user_id", SecurityHelper.getCurrentUserId())
                .eq("to_user_id",userId));
        one.setWhetherToFollow(!(attFansPOS == null));
        return Res.ok(one);
    }


    /**
     * 获取推荐关注老师的列表信息
     * 1.根据当前学生用户 查询所在年级的所有老师
     * 2.直播观看数量最多 @TODO
     * @return 推荐老师列表
     */
    @ApiOperation("获取推荐关注老师的列表信息")
    @GetMapping("/getRecommendedWatchList")
    public Res getRecommendedWatchList(){
        String userRole = UserUtil.getUserRole();
        Integer currentUserId = SecurityHelper.getCurrentUserId();
        if("parent".equals(userRole)){
            ReadUserParentPO userParentPO = userParentService.getOne(new QueryWrapper<ReadUserParentPO>()
                    .eq("parent_id",currentUserId));
            currentUserId = userParentPO.getUserId();
        }
        ReadUserPO userPO = userService.getById(currentUserId);
        Integer clazzId = userPO.getClazzId();
        ReadClazzPO clazz = clazzService.getById(clazzId);

        List<ReadClazzPO> list = clazzService.list(new QueryWrapper<ReadClazzPO>().eq("school_id", userPO.getSchoolId()).eq("grade_id", clazz.getGradeId()));
        List<Integer> clazzIds = list.stream().map(ReadClazzPO::getId).collect(Collectors.toList());
        //该年级的所有老师
        List<ReadTeachClazzPO> teachers = teachClazzService.list(new QueryWrapper<ReadTeachClazzPO>().in("clazz_id", clazzIds));
        List<Integer> AllTeacherIds = teachers.stream().map(ReadTeachClazzPO::getTeacherId).distinct().collect(Collectors.toList());
        //List<Integer> teacherIds = AllTeacherIds.stream().filter(id -> !attIds.contains(id)).distinct().collect(Collectors.toList());
        Integer currentUserIdNew = SecurityHelper.getCurrentUserId();
        Set<Integer> attIds = followUtil.findFollwings(currentUserIdNew.toString()).stream().map(Integer::parseInt).collect(Collectors.toSet());
        List<Integer> teacherIds  = AllTeacherIds.stream()
                .filter(id -> !attIds.contains(id))
                .distinct()
                .collect(Collectors.toList());
        if (teacherIds.size() >0){
            List<ViewUserPO> data = viewUserService.list(new QueryWrapper<ViewUserPO> ().in("user_id",teacherIds).orderByAsc("fans_count"));
            return Res.ok(data);
        }else {
            return Res.ok(new ArrayList<ViewUserPO>());
        }


    }



    /**
     * 获取当月 作业数量
     * @param operaIds 作业ids
     * @return 数量
     */
    private int getOperationCount(List<Integer> operaIds){
        Calendar cale;
        // 获取当月第一天和最后一天
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        // 获取前月的第一天
        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 0);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        String firstDay = format.format(cale.getTime());
        // 获取前月的最后一天
        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 0);
        String lastDay = format.format(cale.getTime());

        return operationService.count(new QueryWrapper<ReadOperationPO>()
                .in("id", operaIds)
                .between("start_time",firstDay,lastDay));
    }


}
